/*----------------------------------------------------------------------------
Owner(s): Shane Whitfield
$Copyright: $
$Id: $
----------------------------------------------------------------------------*/

#include "gomgr.h"
#include "go.h"
#include "go_mobiles.h"
#include "go_playerunits.h"
#include "go_enemies.h"
#include "go_playerweapons.h"
#include "touchmgr.h"
#include "go_path.h"

#include <algorithm>

/*--------------------------------------------------------------------------*/

EClass ClassFromString(const char* i_classStr)
{
	if (!strcmp(i_classStr, "swarmer"))
	{
		return EClass_Swarmer;
	}
	if (!strcmp(i_classStr, "nucleus"))
	{
		return EClass_Nucleus;
	}
	else
	{
		printf("Unknown class name %s", i_classStr);
	}
	
	return EClass_Invaild;
}


/*--------------------------------------------------------------------------*/

CGoMgr::CGoMgr() : super("GoMgr")
{
	m_touchedGo = NULL;
	m_isTouchOfDeath = false;
	m_goNodePlacing = NULL;
}

void CGoMgr::On_Command(const char* i_command, const char* i_parameters)
{
	if (!strcmp(i_command, "deathtouch"))
	{
		m_isTouchOfDeath = atoi(i_parameters);
	}
}

void CGoMgr::OnPreWorldUnload()
{
	//remove all the gos
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		m_gos[igo]->OnPreWorldUnload();
	}
	
	//remove all the gos
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		delete m_gos[igo];
	}
	
	m_gos.clear();
	
	m_goNodePlacing = NULL;
}

bool CGoMgr::On_IsGoPlacingNodePlaced() const
{
	return m_goNodePlacing ? m_goNodePlacing->IsPlaced() : true;
}

int CGoMgr::GetClassCost(EClass i_class) const
{
	switch(i_class)
	{
	case EClass_ExpansionNode:
		{
			return 50;
		}
		break;
	case  EClass_HealStation:
		{
			return 200;
		}
		break;
	case  EClass_BasicWeapon:
		{
			return 100;
		}
		break; 
	case EClass_MiningStation:
		{
			return 100;
		}
		break;
	default:
		{
			printf("Error: class type has no cost!");
			return 0;
		}
		break;
	}
}

void CGoMgr::On_UICreateGoPlacingNode(EClass i_spawnClass, const Vector2f& i_worldPos)
{
	if (m_goNodePlacing)
	{
		printf("Error: A node is already being place and a new one is requested!");
		On_UIDestoryCurrentGoPlacingNode();
	}
	
	m_goNodePlacing = static_cast<CGoNode*>(CreateGo(i_spawnClass, i_worldPos));
}

void CGoMgr::On_UIDestoryCurrentGoPlacingNode()
{
	if (!m_goNodePlacing)
	{
		printf("Error: No node placing, but destroy placing node called");
		return;
	}
	
	DestroyGo(m_goNodePlacing);
	m_goNodePlacing = NULL;	
}

void CGoMgr::Render()
{
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		if (m_gos[igo]->IsInWorld())
		{
			m_gos[igo]->Render();
		}
	}
}

void CGoMgr::Update()
{
	if (m_goNodePlacing && m_goNodePlacing->IsPlaced())
	{
		m_goNodePlacing = NULL;
	}

	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		if (m_gos[igo]->IsInWorld())
		{
			m_gos[igo]->Update();
		}
	}
}

void CGoMgr::DestroyGo(CGo* i_go)
{
	//find the CGO in the array and delete it

	std::vector<CGo*>::iterator iter = std::find(m_gos.begin(), m_gos.end(), i_go);
    if (iter != m_gos.end())
    {
        m_gos.erase(iter);
        delete i_go;
        return;
    }
	
    assert(0);     // error couldn't find i_go. 
}

CGo* CGoMgr::CreateGo(EClass i_class, const Vector2f& i_pos)
{
	CGo* newGo = NULL;
	switch(i_class)
	{
	case EClass_Healer:
		{
			newGo = new CGoHealer();
		}
		break;
	case EClass_Minerals:
		{
			newGo = new CGoMinerals();
		}
		break;
	case EClass_Miner:
		{
			newGo = new CGoMiner();
		}
		break;
	case EClass_MiningStation:
		{
			newGo = new CGoMiningStation();
		}
		break;
	case EClass_HealStation:
		{
			newGo = new CGoHealStation();
		}
		break;
	case EClass_Nucleus:
		{
			newGo = new CGoNucleus();
		}
		break;
	case EClass_ExpansionNode:
		{
			newGo = new CGoExpansionNode();
		}
		break;
	case EClass_BasicWeapon:
		{
			newGo = new CGoWeaponBasic();
		}
		break;
	case EClass_Swarmer:
		{
			newGo = new CGoSwarmer();
		}
		break;
	case EClass_Path:
		{
			newGo = new CGoPath();
		}
		break;
	default:
		{
			//error no such go!
			printf("Error: No go case of given class type");
		}
	}
	
	if (newGo)
	{
		newGo->SetPos(i_pos);
		addGo(newGo);
	}
	
	return newGo;
}

void CGoMgr::addGo(CGo* i_go)
{
	assert(i_go);

	m_gos.push_back(i_go);
}

bool CGoMgr::GetNearConnectionProviderNodes(const Vector2f& i_center, float i_radius, std::vector<CGoNode*>& o_foundNodes, CGoNode* i_ignoreMe)
{
	int nodesFound = 0;
	
	//go through all the game objects and record in that are within the radius check
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		CGo* go = m_gos[igo];
		CGoNode* goNode = static_cast<CGoNode*>(go);
		
		if (go && go->IsInWorld() && go->IsNode() && goNode != i_ignoreMe && 
				goNode->HasConnectionSlot() && Dist(go->GetPos(), i_center) <= i_radius)
		{
			o_foundNodes.push_back(goNode);
			nodesFound++;
		}
	}
	
	return nodesFound != 0;
}

bool CGoMgr::GetNearNodesNotFullHealth(const Vector2f& i_center, float i_radius, std::vector<CGoNode*>& o_foundNodes)
{
	int nodesFound = 0;
	
	//go through all the game objects and record in that are within the radius check
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		CGo* node = m_gos[igo];
		if (node && node->IsInWorld() && node->IsNode() && node->IsAlive() && !node->HasFullHealth() && Dist(node->GetPos(), i_center) <= i_radius)
		{
			o_foundNodes.push_back(static_cast<CGoNode*>(node));
			nodesFound++;
		}
	}
	
	return nodesFound != 0;
}

bool CGoMgr::GetNearEnemies(const Vector2f& i_center, float i_radius, std::vector<CGo*>& o_foundNodes)
{
	int nodesFound = 0;
	
	//go through all the game objects and record in that are within the radius check
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		CGo* go = m_gos[igo];
		if (go->IsInWorld() && go->IsEnemy() && go->IsAlive() && Dist(go->GetPos(), i_center) <= i_radius)
		{
			o_foundNodes.push_back(static_cast<CGo*>(go));
			nodesFound++;
		}
	}
	
	return nodesFound != 0;
}

bool CGoMgr::GetNearMinerals(const Vector2f& i_center, float i_radius, std::vector<CGoMinerals*>& o_foundMinerals)
{
	int countFound = 0;
	
	//go through all the game objects and record in that are within the radius check
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		
		CGo* go = m_gos[igo];
		CGoMinerals* goMineral = static_cast<CGoMinerals*>(go);
		if (go->IsInWorld() && go->IsMinerals() && !goMineral->IsEmpty() && Dist(go->GetPos(), i_center) <= i_radius)
		{
			o_foundMinerals.push_back(goMineral);
			countFound++;
		}
	}
	
	return countFound != 0;
}

bool CGoMgr::GetNearNodes(const Vector2f& i_center, float i_radius, std::vector<CGoNode*>& o_foundNodes)
{
	int nodesFound = 0;
	
	//go through all the game objects and record in that are within the radius check
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		CGo* go = m_gos[igo];
		CGoNode* node = static_cast<CGoNode*>(go);
		if (go && go->IsInWorld() && go->IsNode() && node->IsPlaced() && Dist(node->GetPos(), i_center) <= i_radius)
		{
			o_foundNodes.push_back(node);
			nodesFound++;
		}
	}
	
	return nodesFound != 0;
}

CGoPath* CGoMgr::GetPathByName(const char* i_name)
{
	//go through all the gos and find the one that is path and has this name
	for(int igo = 0; igo < m_gos.size(); ++igo)
	{
		CGo* go = m_gos[igo];
		if (go->GetClass() == EClass_Path)
		{
			CGoPath* path = static_cast<CGoPath*>(go);
			if (!strcmp(path->GetName(), i_name))
			{
				return path;
			}
		}
	}
	
	return NULL;
}

float CGoMgr::GetDepthFromDepthEnum(EDepthLayer i_depthlayer) 
{
	const float layerDelta = 1.0f / EDepthLayer_Count;
	
	if (i_depthlayer < EDepthLayer_Begin || i_depthlayer >= EDepthLayer_Count)
	{
		printf("Error: Unknow layer (%d) given", i_depthlayer);
		return 1.0f;
	}
    
    return layerDelta / (float)i_depthlayer;
}

/*-----------------------------------EOF!-----------------------------------*/ 